﻿#pragma once

namespace
{
#if defined (_WIN32_WCE)
	long const LOG4CPLUS_FILE_NOT_FOUND = ERROR_FILE_NOT_FOUND;
#else
	long const LOG4CPLUS_FILE_NOT_FOUND = ENOENT;
#endif


	static long file_rename(tstring const & src, tstring const & target)
	{
#if defined (UNICODE) && defined (WIN32)
		if (_wrename (src.c_str (), target.c_str ()) == 0)
			return 0;
		else
			return errno;
#else

		if (std::rename(src.c_str (), target.c_str ()) == 0)
			return 0;
		else
			return errno;
#endif
	}


	static long file_remove (tstring const & src)
	{
#if defined (UNICODE) && defined (WIN32)
		if (_wremove (src.c_str ()) == 0)
			return 0;
		else
			return errno;
#else
		if (std::remove (src.c_str ()) == 0)
			return 0;
		else
			return errno;

#endif
	}


	static void rolloverFiles(const tstring& filename, unsigned int maxBackupIndex)
	{
		// Delete the oldest file
		tostringstream buffer;
		buffer << filename << T_TEXT(".") << maxBackupIndex;
		long ret = file_remove(buffer.str ());

		tostringstream source_oss;
		tostringstream target_oss;

		// Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
		for (int i = maxBackupIndex - 1; i >= 1; --i)
		{
			source_oss.str(T_TEXT(""));
			target_oss.str(T_TEXT(""));

			source_oss << filename << T_TEXT(".") << i;
			target_oss << filename << T_TEXT(".") << (i+1);

			tstring const source (source_oss.str());
			tstring const target (target_oss.str());

#if defined (WIN32)
			// Try to remove the target first. It seems it is not
			// possible to rename over existing file.
			ret = file_remove(target);
#endif

			ret = file_rename (source, target);

		}
	} // end rolloverFiles()

}



namespace log4lite {

	class RollingFileAppender : public FileAppender 
	{
	public:
		RollingFileAppender(const tstring& filename, bool immediateFlush = true, long maxFileSize = 10*1024*1024 /* 10 MB */,  int maxBackupIndex = 1)
			: FileAppender(filename, std::ios::app, _immediateFlush)
			: _maxFileSize(maxFileSize)
			, _maxBackupIndex(maxBackupIndex)
		{
			
		}

		~RollingFileAppender()
		{
			
		}

	protected:
		virtual void append(const LogItem& item)
		{
			FileAppender::append(item);
			if (_ofs.tellp() > _maxFileSize) {
				rollover();
			}
			
		}
		void rollover() 
		{
			_ofs.close();
			_ofs.clear(); // reset flags since the C++ standard specified that all the
			// flags should remain unchanged on a close

			// If maxBackups <= 0, then there is no file renaming to be done.
			if (_maxBackupIndex > 0)
			{
				rolloverFiles(_filename, _maxBackupIndex);

				// Rename fileName to fileName.1
				tstring target = _filename + T_TEXT(".1");

				long ret;

#if defined (WIN32)
				// Try to remove the target first. It seems it is not
				// possible to rename over existing file.
				ret = file_remove(target);
#endif

				ret = file_rename (_filename, target);
			}

			// Open it up again in truncation mode
			open(std::ios::out | std::ios::trunc);
		}
	
	private:
		long _maxFileSize;
		int _maxBackupIndex;
	};

	class DailyRollingFileAppender : public FileAppender 
	{
	public:
		DailyRollingFileAppender(const tstring& filename, bool immediateFlush = true, long maxFileSize = 10*1024*1024 /* 10 MB */,  int maxBackupIndex = 1)
			: FileAppender(filename, std::ios::app, _immediateFlush)
		{

		}

	};

}

	